package orm.er;

import orm.infrastructure.interfaces.IAssignable;
import orm.infrastructure.interfaces.IBinarySerialize;
import orm.infrastructure.interfaces.INullable;
import orm.infrastructure.interfaces.IValidable;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * User: Awake
 * Date: 03.05.12
 * Time: 2:22
 * To change this template use File | Settings | File Templates.
 */
public class PersonMock implements IAssignable, IValidable, INullable, IBinarySerialize, Cloneable {

    private static final int FNAME_LENGTH = 50;
    private static final int LNAME_LENGTH = 50;
    private static final String NULL_EXCEPTION = "Can not operate with null objects";
    private static final String NOT_VALID_EXCEPTION = "Can not operate with not valid object";
    private static final String ENCODING = "UTF-16";
    private static final int NULL_VALUE = -1;

    public PersonMock() {

    }

    public PersonMock(int id, String FName, String LName) {
        this.m_id = id;
        this.m_FName = FName;
        this.m_LName = LName;
        this.m_nullable = false;
    }

    /**
     * Creates nullable instance of PersonMock
     *
     * @return nullable PersonMock object
     */

    public static PersonMock getNullableInstance() {
        PersonMock aPersonMock = new PersonMock();
        aPersonMock.m_nullable = true;
        return aPersonMock;
    }

    @Override
    public void assignTo(Object object) {

        if (object != null && object.getClass().equals(PersonMock.class)) {

            PersonMock person = (PersonMock) object;
            person.setID(this.m_id);
            person.setFName(this.m_FName);
            person.setLName(this.m_LName);
        }
    }

    @Override
    public Object clone() {
        PersonMock person = new PersonMock();
        this.assignTo(person);
        return person;
    }

    @Override
    public void writeTo(DataOutputStream outputStream) throws IOException {

        if (!this.Validate()) {
            throw new UnsupportedOperationException(NOT_VALID_EXCEPTION);
        } else {

            outputStream.writeInt(getID());
            if (m_FName == null) {
                outputStream.writeInt(NULL_VALUE);
            } else {
                byte[] firstNameBinaryArray = getFName().getBytes(ENCODING);
                outputStream.writeInt(firstNameBinaryArray.length);
                outputStream.write(firstNameBinaryArray);
            }
            if (m_LName == null) {
                outputStream.writeInt(NULL_VALUE);
            } else {
                byte[] lastNameBinaryArray = getLName().getBytes(ENCODING);
                outputStream.writeInt(lastNameBinaryArray.length);
                outputStream.write(lastNameBinaryArray);
            }
        }
    }

    @Override
    public void readFrom(DataInputStream inputStream) throws IOException {

        if (this.m_nullable) {
            throw new UnsupportedOperationException(NULL_EXCEPTION);
        } else {

            setID(inputStream.readInt());

            int firstNameLength = inputStream.readInt();
            if (firstNameLength >= 0) {
                byte[] firstNameBytes = new byte[firstNameLength];
                inputStream.read(firstNameBytes, 0, firstNameLength);
                String firstName = new String(firstNameBytes, ENCODING);
                setFName(firstName);
            } else {
                setFName(null);
            }

            int lastNameLength = inputStream.readInt();
            if (lastNameLength >= 0) {
                byte[] lastNameBytes = new byte[lastNameLength];
                inputStream.read(lastNameBytes, 0, lastNameLength);
                String lastName = new String(lastNameBytes, ENCODING);
                setLName(lastName);
            } else {
                setLName(null);
            }

        }
    }


    @Override
    public boolean Validate() {
        return !(this == null || m_id < 0 || m_FName == null || m_LName == null);
    }

    @Override
    public boolean isNullable() {
        return m_nullable;
    }

    public int getID() {
        return m_id;
    }

    public void setID(int id) {
        if (m_nullable)
            throw new UnsupportedOperationException(NULL_EXCEPTION);
        this.m_id = id;
    }

    public String getFName() {
        return m_FName;
    }

    public void setFName(String FName) {
        if (m_nullable)
            throw new UnsupportedOperationException(NULL_EXCEPTION);
        if (FName.length() > FNAME_LENGTH)
            FName = FName.substring(0, FNAME_LENGTH - 1);
        this.m_FName = FName;
    }


    public String getLName() {
        return m_LName;
    }

    public void setLName(String LName) {
        if (m_nullable)
            throw new UnsupportedOperationException(NULL_EXCEPTION);

        this.m_LName = (LName.length() > LNAME_LENGTH) ? LName.substring(0, LNAME_LENGTH - 1) : LName;
    }

    private int m_id = 0;
    private String m_FName = null;
    private String m_LName = null;
    private boolean m_nullable = false;
}
